#pragma once
#include <iostream>
#include <memory>
#include <string>
#include <unordered_map>
#include "Connection.hpp"
#include "Multiplex.hpp"

class Reactor
{
    static const int gnum = 64;

private:
    std::unordered_map<int, Connection *> _connections;
    std::unique_ptr<Multiplex> _epoller;
    bool _isRunning;
    struct epoll_event _revs[gnum];

    // Reactor中添加处理socket的方法集合
    // 1. 处理新连接
    handler_t _OnConnect;
    // 2. 处理普通的sockfd，主要是IO处理
    handler_t _OnRecver;
    handler_t _OnSender;
    handler_t _OnExcepter;

public:
    Reactor() : _epoller(std::make_unique<Epoller>()), _isRunning(false) {}
    ~Reactor() {}

    void SetOnConnect(handler_t OnConnect) { _OnConnect = OnConnect; }
    void SetOnNormalHandler(handler_t OnRecver, handler_t OnSender, handler_t OnExcepter)
    {
        _OnRecver = OnRecver;
        _OnSender = OnSender;
        OnExcepter = OnExcepter;
    }

    bool IsConnectionExist(int sockfd)
    {
        return _connections.find(sockfd) != _connections.end();
    }

    void AddConnection(int sockfd, uint32_t events, int type, const InetAddr &addr)
    {
        // 1. 构建Connection
        Connection *conn = new Connection(sockfd);
        conn->SetEvent(events);
        conn->SetType(type);
        conn->SetAddr(addr);
        conn->SetReactor(this);

        if (conn->Type() == ListenConnection)
        {
            conn->RegisterHandler(_OnConnect, nullptr, nullptr);
        }
        else
        {
            conn->RegisterHandler(_OnRecver, _OnSender, _OnExcepter);
        }

        // 2. 托管给epoll
        if (!_epoller->AddEvent(sockfd, events))
            return;

        // 3. 托管给connection
        _connections.insert(std::make_pair(sockfd, conn));
        LOG(INFO, "connection add success, sockfd: %d\n", sockfd);
    }

    void EnableConnection(int sockfd, bool readable, bool writeable)
    {
        if (!IsConnectionExist(sockfd))
        {
            LOG(ERROR, "connection not exist, sockfd: %d\n", sockfd);
            return;
        }

        uint32_t events = ((readable ? EPOLLIN : 0) | (writeable ? EPOLLOUT : 0) | EPOLLET);
        _connections[sockfd]->SetEvent(events);

        _epoller->ModEvent(sockfd, events);
        LOG(INFO, "connection enable success, sockfd: %d\n", sockfd);
    }

    void DelConnection(int sockfd)
    {
        if (!IsConnectionExist(sockfd))
        {
            LOG(ERROR, "connection not exist, sockfd: %d\n", sockfd);
            return;
        }
        // 1. 内核移除对sockfd的关心
        EnableConnection(sockfd, false, false);
        _epoller->DelEvent(sockfd);

        // 2. 关闭sockfd
        _connections[sockfd]->Close();

        // 3. Reactor中移除sockfd
        _connections.erase(sockfd);
        LOG(INFO, "sockfd %d quit, 服务器释放所有资源\n", sockfd);
    }

    void LoopOnce(int timeout)
    {
        int n = _epoller->Wait(_revs, gnum, timeout);
        for (int i = 0; i < n; ++i)
        {
            int sockfd = _revs[i].data.fd;
            uint32_t events = _revs[i].events;

            // tmp
            if (events & EPOLLERR)
                events |= (EPOLLIN | EPOLLOUT);
            if (events & EPOLLHUP)
                events |= (EPOLLIN | EPOLLOUT);

            if (events & EPOLLIN)
            {
                if (IsConnectionExist(sockfd) && _connections[sockfd]->_recver)
                    _connections[sockfd]->_recver(_connections[sockfd]);
            }

            if (events & EPOLLOUT)
            {
                if (IsConnectionExist(sockfd) && _connections[sockfd]->_sender)
                    _connections[sockfd]->_sender(_connections[sockfd]);
            }
        }
    }

    void Dispatcher()
    {
        int timeout = -1;
        _isRunning = true;
        while (_isRunning)
        {
            LoopOnce(timeout);
            // other
            PrintDebug();
        }
        _isRunning = false;
    }

    void PrintDebug()
    {
        std::string fdlist;
        for (auto &conn : _connections)
        {
            fdlist += std::to_string(conn.second->Sockfd()) + " ";
        }
        LOG(DEBUG, "epoll管理的fd列表: %s\n", fdlist.c_str());
    }
};